/*
  This file is part of 'Trivial chess'.

  'Trivial chess' is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  'Trivial chess' is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with 'Trivial chess'.  If not, see <http://www.gnu.org/licenses/>.
*/

/* SVN FILE: $Id$ */
/**
 * @author         $Author$
 * @version        $Rev$
 * @lastrevision   $Date$
 * @filesource     $URL$
 */

//#define BOOST_TEST_MODULE Board
#include <boost/test/unit_test.hpp>
#include "../config.h"
#include "../macros.h"


BOOST_AUTO_TEST_SUITE( BoardTest )

const std::string CAS[] = {
		"KQkq","KQk","KQq","Kkq","Qkq","KQ","Kq","kq","Kk","Qq","Qk","K","Q","k","q","-"
	};

const std::string FENS[] = {
		"r3kb1r/3n1pp1/p6p/2pPp2q/Pp2N3/3B2PP/1PQ2P2/R3K2R w KQkq - 0 8",
		"1k1r3r/pp2qpp1/3b1n1p/3pNQ2/2pP1P2/2N1P3/PP4PP/1K1RR3 b - - 0 15",
		"r2qkb1r/1b3ppp/p3pn2/1p6/1n1P4/1BN2N2/PP2QPPP/R1BR2K1 w kq - 3 30",
		"2r1k2r/2pn1pp1/1p3n1p/p3PP2/4q2B/P1P5/2Q1N1PP/R4RK1 w q - 7 17",
		"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2",
		"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
		"5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 50 40",
		"8/5Bp1/4P3/6pP/1b1k1P2/5K2/8/8 w - - 2 4095",
		"8/1QQ5/1K6/Q7/1Q4qq/5kq1/4q3/8 b - - 46 4040"
	};

const int FENS_COUNT = 9;

BOOST_AUTO_TEST_CASE( testCleanAndIsEmpty ) {
	Board board;
	board.clean();
	FOREACH(Square, square) {
		BOOST_CHECK(board[*square].isNil());
		BOOST_CHECK(board.isEmpty(*square));
	}
}

BOOST_AUTO_TEST_CASE( testGetAndSet ) {
	Board board;
	board.clean();
	FOREACH(Man, man1) {
		FOREACH(Square, square1) {
			board.set(*square1, *man1);
			FOREACH(Man, man2) {
				FOREACH(Square, square2) {
					if ( square1 == square2 )
						continue;

					board.set(*square2, *man2);
					BOOST_CHECK_EQUAL(board[*square2], *man2);
					BOOST_CHECK_EQUAL(board[*square1], *man1);
				}
			}
		}
	}
}

BOOST_AUTO_TEST_CASE( testUnset ) {
	Board board;
	board.clean();
	FOREACH(Man, man1) {
		FOREACH(Square, square1) {
			board.set(*square1, *man1);
			FOREACH(Man, man2) {
				FOREACH(Square, square2) {
					if ( square1 == square2 )
						continue;

					board.set(*square2, *man2);
					board.unset(*square2);
					BOOST_CHECK(board.isEmpty(*square2));
					BOOST_CHECK_EQUAL(board[*square1], *man1);
				}
			}
		}
	}
}

BOOST_AUTO_TEST_CASE( testSideToMove ) {
	Board board;
	board.setSideToMove(Color::WHITE());
	BOOST_CHECK_EQUAL(board.sideToMove(), Color::WHITE());
	board.setSideToMove(Color::BLACK());
	BOOST_CHECK_EQUAL(board.sideToMove(), Color::BLACK());
}

BOOST_AUTO_TEST_CASE( testSetRivalToMove ) {
	Board board;
	board.setSideToMove(Color::WHITE());
	board.setRivalToMove();
	BOOST_CHECK_EQUAL(board.sideToMove(), Color::BLACK());
	board.setRivalToMove();
	BOOST_CHECK_EQUAL(board.sideToMove(), Color::WHITE());
}

BOOST_AUTO_TEST_CASE( testEnpassant ) {
	Board board;
	FOREACH(File, file) {
		Square square = Square(*file, Rank::R6());
		board.setSideToMove(Color::WHITE());
		board.setEnpassant(square);
		BOOST_CHECK_EQUAL(square, board.enpassant());
		board.setSideToMove(Color::BLACK());
		square.setRank(Rank::R3());
		board.setEnpassant(square);
		BOOST_CHECK_EQUAL(square, board.enpassant());
	}
}

BOOST_AUTO_TEST_CASE( testHalfmoveClock ) {
	Board board;
	for ( int i = 0; i <= 50; ++i ) {
		board.setHalfmoveClock(i);
		BOOST_CHECK_EQUAL(i, board.halfmoveClock());
	}
}

BOOST_AUTO_TEST_CASE( testIncHalfmoveClock ) {
	Board board;
	board.setHalfmoveClock(0);
	for ( int i = 1; i <= 50; ++i ) {
		board.incHalfmoveClock();
		BOOST_CHECK_EQUAL(i, board.halfmoveClock());
	}
}

BOOST_AUTO_TEST_CASE( testResetHalfmoveClock ) {
	Board board;
	for ( int i = 1; i <= 50; ++i ) {
		board.setHalfmoveClock(i);
		board.resetHalfmoveClock();
		BOOST_CHECK_EQUAL(0, board.halfmoveClock());
	}
}

BOOST_AUTO_TEST_CASE( testFullmoveNumber ) {
	Board board;
	for ( int i = 0; i < 4096; ++i ) {
		board.setFullmoveNumber(i);
		BOOST_CHECK_EQUAL(i, board.fullmoveNumber());
	}
}

BOOST_AUTO_TEST_CASE( testIncFullmoveNumber ) {
	Board board;
	board.setFullmoveNumber(0);
	for ( int i = 1; i < 4096; ++i ) {
		board.incFullmoveNumber();
		BOOST_CHECK_EQUAL(i, board.fullmoveNumber());
	}
}

BOOST_AUTO_TEST_CASE( testDecFullmoveNumber ) {
	Board board;
	board.setFullmoveNumber(4095);
	for ( int i = 4094; i >= 0; --i ) {
		board.decFullmoveNumber();
		BOOST_CHECK_EQUAL(i, board.fullmoveNumber());
	}
}

BOOST_AUTO_TEST_CASE( testCastlingAvailability ) {
	CastlingAvailability ca;
	Board board;
	for ( int i = 0; i < 16; ++i ) {
		ca.fromStr(CAS[i]);
		board.setCastlingAvailability(ca);
		BOOST_CHECK_EQUAL(board.castlingAvailability(), ca);
	}
}

BOOST_AUTO_TEST_CASE( testToStrAndFromStr ) {
	Board board;
	for ( int i = 0; i < FENS_COUNT; ++i ) {
		board.fromStr(FENS[i]);
		BOOST_CHECK_EQUAL(board.toStr(), FENS[i]);
	}
}


BOOST_AUTO_TEST_SUITE_END()
